/*
 * ResourceLN.java
 *
 * $Id: ResourceLN.java,v 1.1 2008-03-18 12:58:46 mario Exp $
 *
 * Author: Mario García García - Imagos 2007
 */
package org.ceteca.explica.server.installer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.ceteca.explica.core.InterfaceErrors;
import org.ceteca.explica.core.installer.ResourceException;
import org.ceteca.explica.core.installer.ResourceOT;

/**
 * This class implements the resources catalog model. It's a part of the business logic
 * layer and encapsulates the access to the resources tables, providing methods 
 * to query, update, insert or delete resources.
 * <br/>
 * Responsibilities:
 * <li>
 * 	<ul> Provide access to resources metadata (path, version). </ul>
 *  <ul> Query the database by the primary key or by any other query criteria for 
 *  resources. </ul>
 *  <ul> Insert new resources into the catalog. </ul>
 *  <ul> Update resources catalog (paths and versions). </ul>
 *  <ul> Delete resources from the catalog. </ul>
 * </li>
 */
public class ResourceLN {
	// Implementation of Singleton pattern.
	private static ResourceLN instance = null;
	
	/**
	 * Default constructor of the class ResourceLN.
	 */
	private ResourceLN() {
	}
	
	/**
	 * Returns the Singleton instance of class ResourceLN.
	 * @return ResourceLN, the Singleton instance of ResourceLN.
	 */
	public static ResourceLN getInstance() {
		if (instance == null)
			instance = new ResourceLN();
	
		return instance;
	}
	
	/**
	 * Return the resources' list including the info of all the resources stored
	 * in the catalog.
	 * @return List, list of resources.
	 * @throws ResourceException in case any error take place during the
	 * query operation.
	 */
	public List getAllResources() throws ResourceException {
		// Call the DAO to query the database and get the resources' list.
		ResourceDAO dao = new ResourceDAO();
		return dao.getAllResources();
	}
	
	/**
	 * Return the resource metadata.
	 * @param idResource long, internal id of the resource.
	 * @return ResourceOT, resource metadata.
	 * @throws ResourceException in case any error take place during the
	 * query operation.
	 */
	public ResourceOT getResource(long idResource) throws ResourceException {
		// Call the DAO to query the database and get the resource.
		ResourceDAO dao = new ResourceDAO();
		return dao.getResource(idResource);
	}
	
	/**
	 * Return the resource metadata.
	 * @param codResource String, external identification code of the resource.
	 * @return ResourceOT, resource metadata.
	 * @throws ResourceException in case any error take place during the
	 * query operation.
	 */
	public ResourceOT getResource(String codResource) throws ResourceException {
		// Call the DAO to query the database and get the resource.
		ResourceDAO dao = new ResourceDAO();
		return dao.getResource(codResource);
	}
	
	/**
	 * Load the resource stored in the file pointed by resource's path. It returns
	 * the bytes that the resource is made up of.
	 * @param codResource String, external identification code of the resource.
	 * @return byte[], resource data.
	 * @throws ResourceException in case any error take place during the
	 * query operation.
	 */
	public byte[] loadResource(String codResource) throws ResourceException {
		// Get resource metadata.
		ResourceOT resource = ResourceLN.getInstance().getResource(codResource);
		
		if (resource != null && resource.getPath() != null) {
			// Open the file where the resource is stored
			File f = new File(resource.getPath());
			if (!f.exists()) {
				throw new ResourceException(codResource, f.getAbsolutePath(), InterfaceErrors.ERR_RESOURCE_INCORRECT_PATH);
			}
			else if (f.isFile()) {
				InputStream is = null;
				// Open the input stream to read the resource's file
				try {
					is = new FileInputStream(f);
				}
				catch (FileNotFoundException fEx) {
		        	throw new ResourceException(codResource, f.getAbsolutePath(), InterfaceErrors.ERR_RESOURCE_INCORRECT_PATH, fEx);
		        }
				
				// Get the size of the resource's file
		        long length = f.length();
		    
		        // You cannot create an array using a long type.
		        // It needs to be an int type.
		        // Before converting to an int type, check
		        // to ensure that file is not larger than Integer.MAX_VALUE.
		        if (length > Integer.MAX_VALUE) {
		            throw new ResourceException(null, f.getAbsolutePath(), InterfaceErrors.ERR_RESOURCE_TOO_LARGE);
		        }
		    
		        // Create the byte array to hold the data
		        byte[] bytes = new byte[(int)length];
		    
		        // Read in the bytes
		        int offset = 0;
		        int numRead = 0;
		        try {
		        	while (offset < bytes.length
		        			&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
		        		offset += numRead;
		        	}
		        }
		        catch (IOException ioEx) {
		        	throw new ResourceException(codResource, f.getAbsolutePath(), InterfaceErrors.ERR_RESOURCE_NOT_LOADED, ioEx);
		        }
		    
		        // Ensure all the bytes have been read in
		        if (offset < bytes.length) {
		            throw new ResourceException(codResource, f.getAbsolutePath(), InterfaceErrors.ERR_RESOURCE_NOT_LOADED);
		        }
		    
		        // Close the input stream and return bytes
		        try {
		        	is.close();
		        }
		        catch (IOException ioEx) {
		        	throw new ResourceException(codResource, f.getAbsolutePath(), InterfaceErrors.ERR_RESOURCE_NOT_LOADED, ioEx);
		        }
		        
		        return bytes;
			} // if (f is a file)
			else {
				throw new ResourceException(codResource, f.getAbsolutePath(), InterfaceErrors.ERR_RESOURCE_INCORRECT_TYPE);
			} // else (f is not a file)
		} // if (resource exists)
		else
			throw new ResourceException(null, InterfaceErrors.ERR_RESOURCE_NOT_FOUND);
	}

	/**
	 * Get the latest version available of the resource.
	 * @param codResource String, external identification code of the resource.
	 * @return Integer, resource's latest version available.
	 * @throws ResourceException in case any error take place during the
	 * query operation.
	 */
	public Integer getLatestVersion(String codResource) throws ResourceException {
		// Get resource metadata.
		ResourceOT resource = ResourceLN.getInstance().getResource(codResource);
		
		if (resource == null)
			throw new ResourceException(codResource, InterfaceErrors.ERR_RESOURCE_NOT_FOUND);
		else
			return resource.getVersion();
	}
	
	/**
	 * Checks if the resource available at the client is updated to the last version.
	 * @param codResource String, external identification code of the resource.
	 * @param Integer currentVersion, current version of the resource that is
	 * available at the client.
	 * @return boolean, True in case the resource is up to date; False in any
	 * other case.
	 * @throws ResourceException in case any error take place during the
	 * query operation.
	 */
	public boolean isResourceUpdated(String codResource, Integer currentVersion) throws ResourceException {
		// Get the latest version of the resource that has been uploaded in the server.
		Integer latestVersion = ResourceLN.getInstance().getLatestVersion(codResource);
		
		// Check if the current version is the same as the latest in the server
		if (latestVersion == null) {
			throw new ResourceException(codResource, InterfaceErrors.ERR_RESOURCE_INCORRECT_VERSION);
		}
		else if (currentVersion == null)
			return false;
		else
			return (latestVersion.intValue() == currentVersion.intValue());
	}
	
	/**
	 * Return the areas' list including the list of all the modules
	 * belonging to each area.
	 * @return List, list of areas.
	 * @throws ResourceException in case any error take place during the
	 * query operation.
	 */
	public List getAllAreas() throws ResourceException {
		// Call the DAO to query the database and get the areas' list.
		ResourceDAO dao = new ResourceDAO();
		return dao.getAllAreas();
	}
	
	/**
	 * Returns tag Id assigned to CVS source file.
	 */
	public static String getRevision() {
		return "$Id: ResourceLN.java,v 1.1 2008-03-18 12:58:46 mario Exp $";
	}
}
